﻿// Copyright (c) 2012 - 2020 Jared Zheng <jaredz at outlook dot com>
// Buddha Framework is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Create : 2012-12-01 version 0.1 Jared Zheng <jaredz at outlook dot com>
// Update : 2018-12-05 version 3.1.5 Jared Zheng <jaredz at outlook dot com>

#include "stdafx.h"
#include "CenterHandler.h"
#include "BalanceHandler.h"
#include "AuthorDBHandler.h"
#include "AuthorHandler.h"
#include "MasterDBHandler.h"
#include "MasterHandler.h"
#include "GateHandler.h"
#include "ServiceHandler.h"
#include "MainHandler.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// CMainHandler
CMainHandler::CMainHandler(void)
: m_uStart(FALSE)
, m_uLoad(0)
, m_hBusyLoad(false)
, m_hOverLoad(false)
{
    MM_SAFE::Set(m_pSHandler, 0, sizeof(CCommonHandler*) * PAKT_MAX);
    LOG_INFO(GServerConsoleInst->m_FileLog, TF("服务加载器创建完成!"));
}

CMainHandler::~CMainHandler(void)
{
    Exit();
    LOG_INFO(GServerConsoleInst->m_FileLog, TF("服务加载器销毁!"));
}

bool CMainHandler::Init(void)
{
    if (LoadServerHandlers() == false)
    {
        LOG_ERROR(GServerConsoleInst->m_FileLog, TF("服务加载器加载失败!"));
        UnloadServerHandlers();
        return false;
    }

    m_uLoad = 0;
#if (__PLATFORM_TARGET__ == PLATFORM_TARGET_WINDOWS)
    m_hBusyLoad.Open(false, true, UUID_STR( BusyLoad ) );
    m_hOverLoad.Open(false, true, UUID_STR( OverLoad ) );
#else
    m_hBusyLoad.Open(0, UUID_STR( BusyLoad ) );
    m_hOverLoad.Open(0, UUID_STR( OverLoad ) );
#endif
    CEventQueue::CreateTickEvent(CServerConfig::CFG_TIME_UPDATE_ID, GServerConsoleInst->m_Config.GetUpdateTick() * TIMET_XS2XS, *this);

    if (GServerConsoleInst->StartServers())
    {
        m_uStart = TRUE;
#if (__PLATFORM_TARGET__ == PLATFORM_TARGET_WINDOWS)
        size_t stIndex = (size_t)GServerConsoleInst->m_Config.m_strConfigName.Find(TF('\\'), 0, true);
        ++stIndex;
        stIndex = (GServerConsoleInst->m_Config.m_strConfigName.Length() - stIndex);
        CStringFix strTemp = GServerConsoleInst->m_Config.m_strConfigName.Right(stIndex);
        strTemp += TF("---ServerConsole[");

        if (GServerConsoleInst->m_Config.GetLoadServers() & CServerConfig::CFG_LOAD_CENTER)
        {
            strTemp += TF("Center-");
        }
        if (GServerConsoleInst->m_Config.GetLoadServers() & CServerConfig::CFG_LOAD_BALANCE)
        {
            strTemp += TF("Balance-");
        }
        if (GServerConsoleInst->m_Config.GetLoadServers() & CServerConfig::CFG_LOAD_AUTHORDB)
        {
            strTemp += TF("AuthorDB-");
        }
        if (GServerConsoleInst->m_Config.GetLoadServers() & CServerConfig::CFG_LOAD_AUTHOR)
        {
            strTemp += TF("Author-");
        }
        if (GServerConsoleInst->m_Config.GetLoadServers() & CServerConfig::CFG_LOAD_MASTERDB)
        {
            strTemp += TF("MasterDB-");
        }
        if (GServerConsoleInst->m_Config.GetLoadServers() & CServerConfig::CFG_LOAD_MASTER)
        {
            strTemp += TF("Master-");
        }
        if (GServerConsoleInst->m_Config.GetLoadServers() & CServerConfig::CFG_LOAD_SERVICE)
        {
            strTemp += TF("Service-");
        }
        if (GServerConsoleInst->m_Config.GetLoadServers() & CServerConfig::CFG_LOAD_GATE)
        {
            strTemp += TF("Gate-");
        }
        strTemp.TrimRight(TF('-'));
        strTemp += TF("]");
        ::SetConsoleTitle(*strTemp);
#endif
        UpdateServerHandlers();
        return true;
    }
    else
    {
        UnloadServerHandlers();
        return false;
    }
}

void CMainHandler::Exit(void)
{
    m_uStart = FALSE;
    m_uLoad  = 0;
    m_hBusyLoad.Close();
    m_hOverLoad.Close();

    CEventQueue::DestroyTickEvent(CServerConfig::CFG_TIME_UPDATE_ID);

    UnloadServerHandlers();
}

UInt CMainHandler::OnHandle(Int, uintptr_t, ULLong)
{
    return RET_FAIL;
}

UInt CMainHandler::OnHandle(Int, CEventBase&, ULLong)
{
    return RET_FAIL;
}

UInt CMainHandler::OnHandle(Int, CStream&, ULLong)
{
    return RET_FAIL;
}

UInt CMainHandler::OnHandle(Int nEvent, UInt uCount)
{
    if (m_uStart == FALSE)
    {
        return RET_OKAY;
    }
    UInt uLoad = 0;
    if (m_hOverLoad.Wait(100) == RET_OKAY)
    {
        DEV_DUMP(TF("!!!!!!!!![服务加载器]检测到和外网连接异常!!!!!!!!!"));
        uLoad = DATAD_OVER_LOAD;
    }
    else if (m_hBusyLoad.Wait(100) == RET_OKAY)
    {
        DEV_DUMP(TF("!!!!!!!!![服务加载器]检测到和外网连接高延迟!!!!!!!!!"));
        uLoad = DATAD_BUSY_LOAD;
    }
    if (nEvent == CServerConfig::CFG_TIME_UPDATE_ID)
    {
        for (Int i = 0; i < PAKT_MAX; ++i)
        {
            if (m_pSHandler[i] != nullptr)
            {
                m_pSHandler[i]->OnHandle(nEvent, uCount);
                if (m_uLoad != uLoad)
                {
                    m_pSHandler[i]->GetServer()->Command(TF("WLanStatus"), uLoad);
                }
            }
        }
    }
    if (m_uLoad != uLoad)
    {
        m_uLoad = uLoad;
    }
    return RET_OKAY;
}

bool CMainHandler::LoadServerHandlers(void)
{
    for (Int i = 0; i < PAKT_MAX; ++i)
    {
        if (LoadServerHandler((1 << i), i) == false)
        {
            return false;
        }
    }
    return true;
}

void CMainHandler::UpdateServerHandlers(bool bStart)
{
    for (Int i = 0; i < PAKT_MAX; ++i)
    {
        if (m_pSHandler[i] != nullptr)
        {
            m_pSHandler[i]->OnHandle(PAKE_LIVE, bStart, 0);
        }
    }
}

void CMainHandler::UnloadServerHandlers(void)
{
    for (Int i = 0; i < PAKT_MAX; ++i)
    {
        if (m_pSHandler[i] != nullptr)
        {
            MDELETE m_pSHandler[i];
            m_pSHandler[i] = nullptr;
        }
    }
}

bool CMainHandler::CreateServerHandler(Int nIndex)
{
    if (m_pSHandler[nIndex] == nullptr)
    {
        switch (nIndex)
        {
        case PAKT_CENTER:
            {
                m_pSHandler[nIndex] = MNEW CCenterHandler;
            }
            break;
        case PAKT_BALANCE:
            {
                m_pSHandler[nIndex] = MNEW CBalanceHandler;
            }
            break;
        case PAKT_AUTHORDB:
            {
                m_pSHandler[nIndex] = MNEW CAuthorDBHandler;
            }
            break;
        case PAKT_AUTHOR:
            {
                m_pSHandler[nIndex] = MNEW CAuthorHandler;
            }
            break;
        case PAKT_MASTERDB:
            {
                m_pSHandler[nIndex] = MNEW CMasterDBHandler;
            }
            break;
        case PAKT_MASTER:
            {
                m_pSHandler[nIndex] = MNEW CMasterHandler;
            }
            break;
        case PAKT_SERVICE:
            {
                m_pSHandler[nIndex] = MNEW CServiceHandler;
            }
            break;
        case PAKT_GATE:
            {
                m_pSHandler[nIndex] = MNEW CGateHandler;
            }
            break;
        default:
            {
                //assert(0);
            }
        }
    }
    return (m_pSHandler[nIndex] != nullptr);
}

bool CMainHandler::LoadServerHandler(Int nLoad, Int nIndex)
{
    if (GServerConsoleInst->m_Config.GetLoadServers() & nLoad)
    {
        if (CreateServerHandler(nIndex))
        {
            if (GServerConsoleInst->LoadServer(nLoad, m_pSHandler[nIndex]) == true)
            {
                return true;
            }
        }
        if (m_pSHandler[nIndex] != nullptr)
        {
            MDELETE m_pSHandler[nIndex];
            m_pSHandler[nIndex] = nullptr;
        }
        return false;
    }
    return true;
}

